﻿using System;
using StockholmsStad.Data.Entity;
using StockholmsStad.Utilities.Exceptions;
using StockholmsStad.Runtime.Serialization.DataContract.Enums;
using Booking = StockholmsStad.Runtime.Serialization.DataContract.Booking;
using StockholmsStad.Utilities.Enums;

namespace StockholmsStad.Data.ContractFactory
{
    /// <summary>
    /// Konvertering befintligt dataobjekt till kontraktsobjekt
    /// </summary>
    internal class BookingFactory
    {
        public OrdinaryBooking CreateOrdinaryBookingEntityObject(Booking booking, TimeBlock timeblock, Ticket ticket)
        {
            var bookingEntity = new Entity.Booking {Ticket = ticket};
            var ordinaryBooking = new OrdinaryBooking();
            UpdateEntityObject(booking, bookingEntity, ordinaryBooking, timeblock);
            return ordinaryBooking;
        }

        public IndividualBooking CreateIndividualBookingEntityObject(Booking booking, Minister minister, Ticket ticket)
        {
            var bookingEntity = new Entity.Booking { Ticket = ticket };
            var individualBooking = new IndividualBooking();
            UpdateEntityObject(booking, bookingEntity, individualBooking, minister);
            return individualBooking;
        }

        public void UpdateEntityObject(Booking booking, Entity.Booking bookingEntity, 
            IndividualBooking individualBookingEntity, Minister minister)
        {
            individualBookingEntity.Booking = bookingEntity;
            individualBookingEntity.Date = booking.DateTime.StartDateTime;
            individualBookingEntity.Minister = minister;
        }

        public void UpdateEntityObject(Booking booking, Entity.Booking bookingEntity, 
            OrdinaryBooking ordinaryBookingEntity, TimeBlock timeblock)
        {
            ordinaryBookingEntity.Booking = bookingEntity;
            ordinaryBookingEntity.TimeBlock = timeblock;
        }

        public Booking CreateContractObject(Entity.Booking bookingEntity, Booking contractBooking,
            OrdinaryBooking ordinaryBookingEntity, IndividualBooking individualBookingEntity)
        {
            if (bookingEntity == null)
                return null;

            //Booking kan vara endast PreferredDates
            //if (ordinaryBookingEntity == null && individualBookingEntity == null)
            //{
            //    throw new StockholmStadSystemException(SystemErrorCode.BookingMustBeEitherOrdinaryOrIndividual);
            //}
            if (ordinaryBookingEntity != null && individualBookingEntity != null)
            {
                throw new StockholmStadSystemException(SystemErrorCode.BookingMustBeEitherOrdinaryOrIndividual);
            }

            if(contractBooking == null)
            {
                contractBooking = new Booking();
            }

            if (ordinaryBookingEntity != null)
            {
                contractBooking.CeremonyType = CeremonyType.Ordinary;
                contractBooking.MinisterCode = null;
                contractBooking.DateTime = CreateContractTimeBlock(ordinaryBookingEntity);
            }
            else if (individualBookingEntity != null)
            {
                contractBooking.CeremonyType = CeremonyType.Individual;
                contractBooking.MinisterCode = individualBookingEntity.Minister.MinisterCode;
                contractBooking.DateTime = CreateContractTimeBlock(individualBookingEntity);
            }

            contractBooking.BookingId = bookingEntity.BookingId;

            return contractBooking;
        }

        private static Runtime.Serialization.DataContract.TimeBlock CreateContractTimeBlock(
            IndividualBooking individualBookingEntity)
        {
            return new Runtime.Serialization.DataContract.TimeBlock
                       {
                           StartDateTime = individualBookingEntity.Date,
                       };
        }

        private static Runtime.Serialization.DataContract.TimeBlock CreateContractTimeBlock(
            OrdinaryBooking ordinaryBookingEntity)
        {
            if (ordinaryBookingEntity == null || ordinaryBookingEntity.TimeBlock == null)
                return null;
            return new Runtime.Serialization.DataContract.TimeBlock
                       {
                           StartDateTime = ordinaryBookingEntity.TimeBlock.StartDateTime,
                       };
        }

        private static Runtime.Serialization.DataContract.TimeBlock CreateContractTimeBlock(DateTime? date)
        {
            if (date == null)
                return null;
            return new Runtime.Serialization.DataContract.TimeBlock
                       {
                           StartDateTime = date.Value,
                       };
        }

        public Runtime.Serialization.DataContract.TimeBlock CreateContractTimeBlock(TimeBlock block)
        {
            var contract = new Runtime.Serialization.DataContract.TimeBlock
                               {
                                   TimeBlockId = block.TimeBlockId,
                                   StartDateTime = block.StartDateTime,
                               };
            return contract;
        }
    }
}